<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>贝塞尔曲线</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
    <div id="app">{{title}}
        <div id='wrap' style="width: 700;height: 900px;border: 2px solid #000;margin: 5px auto 0;">
            <svg xmlns="http://www.w3.org/2000/svg" width='700' height='900'>
                <g>
                    <!--C命令：三次贝塞尔曲线 (x1,y1,x2,y2,x,y)/ x1,y1 控制点一 /x2,y2 控制点二 /x,y 结束点 -->
                    <path :d='bz' style="stroke:red;stroke-width:1;fill:none"></path>
                    <line :x1="sx" :y1="sy" :x2="ex" :y2="ey" stroke-dasharray="2 2" stroke="green" />
                    <polyline fill="none" stroke="black" :points="points" />
                </g>
                <g :transform="translateStart">
                    <!-- 箭头指示 -->
                    <polygon fill='#0075ff' points='0 5,0 -5,15 0' :transform="rotate">
                    </polygon>
                    <circle r='5' class='dot-circle index-circle' style='fill:red' @mousedown="mousedown($event)"
                        @mouseup='mouseup($event)' id="start"></circle>
                    <text x='5px' y='10px'>[{{sx + ',' + sy}}]</text>
                </g>

                <g v-for='(dot,index) in dc' :data-index="index">
                    <g class='dot-g' :transform="translate(dot.x, dot.y)">
                        <circle r='5' class='dot-circle' style="fill: gray;" @mousedown="mousedown($event)"
                            @mouseup='mouseup($event)' :id="index"></circle>
                        <text x='5px' y='10px'>[{{dot.x + ',' + dot.y}}]</text>
                    </g>
                </g>

                <g :transform="translateEnd">
                    <circle r='5' class='dot-circle index-circle' style='fill:red' @mousedown="mousedown($event)"
                        @mouseup='mouseup($event)' id="end"></circle>
                    <text x='5px' y='10px'>[{{ex + ',' + ey}}]</text>
                </g>
            </svg>
        </div>

        <div style='display:flex;justify-content:center;align-items:flex-start;flex-wrap:wrap;padding:10px'>
            <button @click='addDot()' style='width:70%'>添加一个控制点</button>
            <ul style='width:100%;cursor:default'>
                <li>
                    起点 :
                    <input type="number" v-model.number='sx'>
                    ,
                    <input type="number" v-model.number='sy'>
                </li>
                <li>
                    终点 :
                    <input type="number" v-model.number='ex'>
                    ,
                    <input type="number" v-model.number='ey'>
                </li>
                <li v-for='(dot,index) in dc'>
                    {{index}} :
                    <input type="number" v-model.number.number='dot.x'>
                    <input type="number" v-model.number.number='dot.y'>
                    <!-- {{dot.x}} , {{dot.y}} -->
                    <button @click='deleteDot(index)'>×</button>
                </li>
            </ul>
        </div>
    </div>
    <script text="text/javascript">
        String.prototype.format = function () {
            if (arguments.length == 0)
                return this;
            for (var s = this, i = 0; i < arguments.length; i++)
                s = s.replace(new RegExp("\\{" + i + "\\}", "g"), arguments[i]);
            return s;
        };
        var app = new Vue({
            el: '#app',
            data: {
                title: "三次贝塞尔曲线",
                sx: 305,
                sy: 726,
                ex: 192,
                ey: 348,
                dc: [{ x: 460, y: 427 },
                { x: 174, y: 610 }],
            },
            computed: {
                bz() {
                    let c = " ";
                    if (this.dc.length > 0) c += "C";
                    for (let dot of this.dc) {
                        c += dot.x + " " + dot.y + " "
                    }
                    return "M" + this.sx + " " + this.sy + c + this.ex + " " + this.ey;
                },
                points() {
                    let c = " ";
                    for (let dot of this.dc) {
                        c += dot.x + " " + dot.y + " "
                    }
                    return this.sx + " " + this.sy + c + this.ex + " " + this.ey;
                },
                //箭头旋转的角度
                rotate() {
                    let distanceX = this.ex - this.sx,
                        distanceY = this.ey - this.sy;

                    let rota = Math.atan2(distanceY, distanceX) * 180 / Math.PI;
                    return "rotate({0}, 0, 0)".format(rota);
                },
                translateStart() {
                    return "translate({0}, {1})".format(this.sx, this.sy);
                },
                translateEnd() {
                    return "translate({0}, {1})".format(this.ex, this.ey);
                },
            },
            methods: {
                translate(x, y) {
                    return "translate({0}, {1})".format(x, y);
                },
                //添加一个控制点
                addDot: function () {
                    this.dc.push({
                        x: this.endX,
                        y: this.endY,
                    });
                },
                //删除一个控制点
                deleteDot: function (index) {
                    this.dc.splice(index, 1);
                },
                mousedown: function (event) {
                    var event = event || window.event;
                    // console.log(event);
                    var _target = event.target
                    var startx = event.clientX;
                    var starty = event.clientY;
                    var vm = this;
                    var sb_bkx = startx - event.offsetX;
                    var sb_bky = starty - event.offsetY;
                    var ww = document.documentElement.clientWidth;
                    var wh = window.innerHeight;
                    if (event.preventDefault) {
                        event.preventDefault();
                    } else {
                        event.returnValue = false;
                    };
                    document.onmousemove = function (ev) {
                        var event = ev || window.event;
                        var scrolltop = document.documentElement.scrollTop || document.body.scrollTop;
                        if (event.clientY < 0 || event.clientX < 0 || event.clientY > wh || event.clientX > ww) {
                            return false;
                        };
                        var endx = event.clientX - sb_bkx;
                        var endy = event.clientY - sb_bky;
                        // console.log(event);
                        if ("start" === _target.id) {
                            vm.sx = endx;
                            vm.sy = endy;
                        } else if ("end" == _target.id) {
                            vm.ex = endx;
                            vm.ey = endy;
                        } else {
                            vm.dc[_target.id].x = endx;
                            vm.dc[_target.id].y = endy;
                        }
                    }
                },
                mouseup: function (e) {
                    document.onmousemove = null;
                }
            },
        });
    </script>
</body>